package com.eastmoney.emis.edda.domain.service.edda.impl;

import com.eastmoney.emis.edda.config.HsbcEddaConfig;
import com.eastmoney.emis.edda.domain.entity.EddaApply;
import com.eastmoney.emis.edda.domain.entity.EddaBind;
import com.eastmoney.emis.edda.domain.event.EddaAuthEnquiryEvent;
import com.eastmoney.emis.edda.domain.event.EventPublisher;
import com.eastmoney.emis.edda.domain.repository.HsbcEddaRepository;
import com.eastmoney.emis.edda.domain.service.edda.EddaAuthStatusService;
import com.eastmoney.emis.edda.domain.valueobject.EddaApplyStatus;
import com.eastmoney.emis.edda.domain.valueobject.MandateStatus;
import com.eastmoney.emis.edda.infrastructure.edda.service.HsbcApiErrorResolver;
import com.eastmoney.emis.edda.infrastructure.hsbc.HsbcEddaApi;
import com.eastmoney.emis.edda.infrastructure.hsbc.dto.AccountDto;
import com.eastmoney.emis.edda.infrastructure.hsbc.dto.AuthEnquiryReq;
import com.eastmoney.emis.edda.infrastructure.hsbc.dto.AuthEnquiryResp;
import com.eastmoney.emis.edda.infrastructure.message.MessageSender;
import com.eastmoney.emis.edda.task.edda.EddaAuthEnquiryTask;
import com.eastmoney.emis.logger.LoggerFactory;
import com.eastmoney.emis.utils.common.exception.PrintExceptionInfo;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;

/**
 * @description: Description
 * @projectName: EDDA-HSBC
 * @package: com.eastmoney.emis.edda.domain.service.edda
 * @author: 汪程程
 * @date: 2022/10/13 1:06 PM
 * @version: 1.0
 */
@Service
public class EddaAuthStatusServiceImpl implements EddaAuthStatusService {

    private static final Integer VALID_DAYS = 20;
    private static final Logger log = LoggerFactory.getLogger(EddaAuthStatusServiceImpl.class);
    @Autowired
    private HsbcEddaConfig config;
    @Autowired
    private HsbcEddaRepository hsbcEddaRepository;
    @Autowired
    private HsbcEddaApi hsbcEddaApi;
    @Autowired
    private EventPublisher eventPublisher;
    @Autowired
    private HsbcApiErrorResolver errorResolver;
    @Autowired
    private MessageSender sender;

    @Override
    public void reload(EddaAuthEnquiryTask task) {
        EddaApply eddaApply = task.getEddaApply();
        AuthEnquiryReq enquiryReq = new AuthEnquiryReq(eddaApply.getRegisterId(), new AccountDto(config.getCreditorAccount()));
        AuthEnquiryResp authEnquiryResp = hsbcEddaApi.authorizationStatus(enquiryReq);
        EddaBind eddaBind = hsbcEddaRepository.findEddaBindByClientIdAndBankAccount(
                eddaApply.getClientId(), eddaApply.getBankCode(), eddaApply.getBankAccount());

        eddaApply.setRejectReasonCode(authEnquiryResp.rejectReasonCode());
        authEnquiryResp.onSuccess(r -> {
            boolean changeStatus = eddaApply.changeStatus(MandateStatus.parse(authEnquiryResp.MandateStatus));
            // 状态更新 日期更新
            if (eddaApply.success() && changeStatus) {
                eddaApply.setGrantStartDate(LocalDate.now());
            }
            eddaApply.setMandateId(authEnquiryResp.MandateIdentification);
            hsbcEddaRepository.save(eddaApply);
            if (!eddaBind.finished() && changeStatus) {
                exceptionWrapper(() -> sender.send(eddaApply, false));
            }
        }).onFail(r -> {
            eddaApply.status(EddaApplyStatus.FAIL);
            hsbcEddaRepository.save(eddaApply);
            if (!eddaBind.finished()) {
                exceptionWrapper(() -> sender.send(eddaApply, false));
            }
        });
        updateEddaBind(eddaBind, eddaApply);
        publishAuthQueryEvent(task, authEnquiryResp);

        // 超过 VALID_DAYS 天以上了
        if (isPastDeadline(eddaApply)) {
            eddaApply.status(EddaApplyStatus.INVALID);
            hsbcEddaRepository.save(eddaApply);
            updateEddaBind(eddaBind, eddaApply);
            EddaAuthEnquiryEvent event = new EddaAuthEnquiryEvent(eddaApply);
            event.setResult("authorization period exceeds 20 days");
            event.setProcessUid(task.getProcessUid());
            event.setProcessUserName(task.getProcessUserName());
            eventPublisher.publish(event);
        }

    }

    private static boolean isPastDeadline(EddaApply eddaApply) {
        EddaApplyStatus applyStatus = EddaApplyStatus.parse(eddaApply.getStatus());
        return applyStatus == EddaApplyStatus.PROCESSING &&
                LocalDateTime.now().minusDays(VALID_DAYS).isAfter(eddaApply.getCreatedTime());
    }


    private void exceptionWrapper(Runnable execute) {
        try {
            execute.run();
        } catch (Exception e) {
            log.error(PrintExceptionInfo.printErrorInfo(e));
        }
    }

    private void updateEddaBind(EddaBind eddaBind, EddaApply eddaApply) {
        if (eddaBind == null) {
            log.error("edda bind not exist, edda-apply id = {}", eddaApply.getEid());
            return;
        }
        if (eddaApply.success()) {
            eddaBind.finish(eddaApply);
            hsbcEddaRepository.save(eddaBind);
            return;
        }
        if (eddaBind.finished() && !eddaBind.getRegisterId().equals(eddaApply.getRegisterId())) {
            return;
        }
        if (eddaApply.fail()) {
            eddaBind.fail(eddaApply);
            hsbcEddaRepository.save(eddaBind);
        }
    }

    private void publishAuthQueryEvent(EddaAuthEnquiryTask task, AuthEnquiryResp authEnquiryResp) {
        EddaAuthEnquiryEvent event = new EddaAuthEnquiryEvent(task.getEddaApply());
        event.setResult(authEnquiryResp.result());
        event.setNote(authEnquiryResp.contextString());
        event.setProcessUid(task.getProcessUid());
        event.setProcessUserName(task.getProcessUserName());
        eventPublisher.publish(event);
    }
}
